#pragma once

#ifndef __TPL_CONCEPTS__
#define __TPL_CONCEPTS__

namespace Concepts
{
	struct Concept 
	{
		virtual ~Concept() {};
	};

	template<class T>
	struct Require
	{
		using tag = typename T::Concept;
#ifdef __GNUC__
		const T value = T{};
#endif // __GNUC__
	};

#define DefineConcept(name, types, body) template types \
	struct name : Concepts::Concept	\
	{						\
		struct Concept {};\
		virtual ~name() \
		body				\
	};
#define ConceptParams(...) <__VA_ARGS__>
#define ConceptRequires(...)  __VA_ARGS__

#ifdef __GNUC__
#define __CPT_CONCAT(X,Y) X##Y
#define __I_CONCAT(X,Y) __CPT_CONCAT(X,Y)
#define require(...) Concepts::Require<__VA_ARGS__> __I_CONCAT(__require,__COUNTER__) = {}
#else
#define require(...) Concepts::Require<__VA_ARGS__>::tag
#endif // __GNUC__

} // namespace Concepts

#endif // __TPL_CONCEPTS__